package com.antler.smt.admin.advice;

import com.antler.smt.admin.config.ResourceConfig;
import com.antler.smt.admin.utils.MailUtil;
import com.antler.smt.enums.ResultCodeEnum;
import com.antler.smt.exception.ParamValidateException;
import com.antler.smt.exception.TransactionException;
import com.antler.smt.exception.VerificationException;
import com.antler.smt.response.base.Result;
import com.antler.smt.utils.JacksonUtil;
import com.antler.smt.utils.LogUtil;
import com.antler.smt.utils.StringUtil;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 异常处理
 *
 * @author vic
 * @date 2018-01-16 14:44
 */
@ControllerAdvice
@ResponseBody
public class ExceptionHandlerAdvice implements ResponseBodyAdvice {

    private ThreadLocal<Object> modelHolder = new ThreadLocal<>();

    /**
     * 邮件工具
     */

    @Autowired
    private MailUtil mailUtil;

    @Autowired
    private ResourceConfig resourceConfig;

    /**
     * 日志
     */
    private static Logger log = LogUtil.get();

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handleIllegalParamException(MethodArgumentNotValidException e, HttpServletRequest request) {
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        String tips = "参数不合法";
        if (errors.size() > 0) {
            tips = errors.get(0).getDefaultMessage();
        }
        log.error(tips, e);
        mailUtil.sendSimpleMail(resourceConfig.getAlarmMail(), "接口异常邮件提醒：" + e.getMessage(), "uri=" + request.getRequestURI() + "| requestBody=" + JacksonUtil.toJSon(modelHolder.get()));
        return new Result(ResultCodeEnum.REQUEST_PARAM_ERROR, tips);
    }

    @ExceptionHandler(ParamValidateException.class)
    public Result handleIllegalParamException(ParamValidateException e, HttpServletRequest request) {
        String tips = "缺少请求参数";
        if (!StringUtil.isEmpty(e.getMessage())) {
            tips = e.getMessage();
        }
        log.error(tips, e);
        mailUtil.sendSimpleMail(resourceConfig.getAlarmMail(), "接口异常邮件提醒：" + e.getMessage(), "uri=" + request.getRequestURI() + "| requestBody=" + JacksonUtil.toJSon(modelHolder.get()));
        return new Result(ResultCodeEnum.REQUEST_PARAM_LACK, tips);
    }

    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e, HttpServletRequest request) {
        log.error("uri={} | requestBody={}", request.getRequestURI(), JacksonUtil.toJSon(modelHolder.get()), e);
        mailUtil.sendSimpleMail(resourceConfig.getAlarmMail(), "接口异常邮件提醒：" + e.getMessage(), "uri=" + request.getRequestURI() + "| requestBody=" + JacksonUtil.toJSon(modelHolder.get()));
        if (e instanceof HttpRequestMethodNotSupportedException) {
            return new Result(ResultCodeEnum.SYSTEM_EXCEPTION, "Http请求Method不对，请查看接口文档！");
        } else if (e instanceof HttpMediaTypeNotSupportedException) {
            return new Result(ResultCodeEnum.SYSTEM_EXCEPTION, "Http请求Content type不对，请查看接口文档！");
        } else if (e instanceof UnauthorizedException) {
            return new Result(ResultCodeEnum.QUERY_DATA_ERROR, "该用户没有权限");
        } else if (e instanceof TransactionException) {
            return new Result(((TransactionException) e).getCode(), e.getMessage());
        } else if (e instanceof VerificationException) {
            return new Result(((VerificationException) e).getCode(), e.getMessage());
        }
        return new Result(ResultCodeEnum.UNKNOWN_ERROR, "");
    }

    @InitBinder
    public void initBinder(WebDataBinder webDataBinder) {
        // ModelHolder 初始化
        modelHolder.set(webDataBinder.getTarget());
    }

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // ModelHolder 清理
        modelHolder.remove();
        return body;
    }
}
